/***************************************************************************
 *   Copyright (C) 2012                                                    *
 *   Anatole Duprat <anatole.duprat@gmail.com>                             *
 *   Charles Bulckaen  <xtrium@frequency.fr>                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License           *
 *   as published by the Free Software Foundation; either version 2        *
 *   of the License, or (at your option) any later version.                *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
 ***************************************************************************/



#include "mainwindow.hh"
#include "ui_mainwindow.h"

#include "renderwidget.hh"
#include "playerwidget.hh"
#include "curveeditorwidget.hh"
#include "sceneeditorwidget.hh"
#include "sceneeditortreeitem.hh"
#include "shadereditorwidget.hh"
#include "curvepointitem.hh"
#include "videoexportwidget.hh"


MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);


    _pw = new PlayerWidget();
    ui->statusBar->insertPermanentWidget(0, _pw, 99);
    ui->statusBar->setSizeGripEnabled(false);

    _sew = new SceneEditorWidget(ui->renderWidget);
    _sew->setSceneTree(ui->renderWidget->sceneTree());

    CurveEditorWidget::preinitCurves(_sew->getAllParameters(), _sew->getAllMappedValues(), _sew->getAllDefaultValues());
    _cew = new CurveEditorWidget();
    addDockWidget(Qt::BottomDockWidgetArea, _cew);
    connect(_sew, SIGNAL(sceneParameterSelectionChanged(QString)), _cew, SLOT(setCurve(QString)));

    addDockWidget(Qt::BottomDockWidgetArea, _sew);

    _shew = new ShaderEditorWidget();
    addDockWidget(Qt::LeftDockWidgetArea, _shew);

    _vew = new VideoExportWidget(ui->renderWidget, _cew);

    connect(ui->actionRender, SIGNAL(triggered()), ui->renderWidget, SLOT(show()));
    connect(ui->actionCurve_editor, SIGNAL(triggered()), _cew, SLOT(hide()));
    connect(ui->actionScene_editor, SIGNAL(triggered()), _sew, SLOT(hide()));
    connect(ui->actionMusic_player, SIGNAL(triggered()), _pw, SLOT(hide()));
    connect(ui->actionShader_editor, SIGNAL(triggered()), _shew, SLOT(hide()));
    connect(ui->actionExport_as_video, SIGNAL(triggered()), _vew, SLOT(show()));


    connect(_pw, SIGNAL(songTimeChanged(float)), _cew, SLOT(setDemoTime(float)));
    connect(_pw, SIGNAL(followTimeBarChanged(bool)), _cew, SLOT(setFollowTimeBar(bool)));
    connect(_pw, SIGNAL(displayWaveformChanged(bool)), _cew, SLOT(setDisplayWaveform(bool)));
    connect(_pw, SIGNAL(newAudiogramAvailable()), _cew, SLOT(getNewAudiogram()));
    connect(_cew, SIGNAL(musicTimeChanged(unsigned int)), _pw, SLOT(mediaSeek(unsigned int)));
    connect(_cew, SIGNAL(musicTimeChanged(unsigned int)), ui->renderWidget, SLOT(setDemoTime(unsigned int)));
    connect(_sew, SIGNAL(demoSizeRTTChanged(int,int)), ui->renderWidget, SLOT(setSizeRTT(int,int)));
    connect(_sew, SIGNAL(demoCameraChanged(int)), ui->renderWidget, SLOT(setCamera(int)));
    connect(_shew, SIGNAL(shaderChanged(QString, QString)), ui->renderWidget, SLOT(CompilShader(QString,QString)));
    connect(_shew, SIGNAL(shaderPostChanged(QString, QString)), ui->renderWidget, SLOT(CompilPostShader(QString,QString)));
    connect(ui->renderWidget, SIGNAL(shaderSceneStatus(QString)), _shew, SLOT(setSceneStatus(QString)));
        connect(ui->renderWidget, SIGNAL(shaderPostStatus(QString)), _shew, SLOT(setPostStatus(QString)));
    connect(ui->renderWidget, SIGNAL(setFPSLabel(QString)), _sew, SLOT(setFPSLabel(QString)));
    connect(_sew, SIGNAL(makeWaypoint()), ui->renderWidget, SLOT(emitMakeWaypoint()));
    connect(ui->renderWidget, SIGNAL(makeWaypoint(float,float,float,float,float,float)), _cew, SLOT(makeWaypoint(float,float,float,float,float,float)));



    _cutShortcut = new QShortcut(QKeySequence(tr("Ctrl+X")), this);
    _copyShortcut = new QShortcut(QKeySequence(tr("Ctrl+C")), this);
    _pasteShortcut = new QShortcut(QKeySequence(tr("Ctrl+V")), this);
    _freeflyShortcut = new QShortcut(QKeySequence(tr("Shift+F")), this);
    connect(_cutShortcut, SIGNAL(activated()), _cew, SLOT(cutSelectedPoints()));
    connect(_copyShortcut, SIGNAL(activated()), _cew, SLOT(copySelectedPoints()));
    connect(_pasteShortcut, SIGNAL(activated()), _cew, SLOT(pasteSelectedPoints()));
    connect(_freeflyShortcut, SIGNAL(activated()), ui->renderWidget, SLOT(startCameraFreefly()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::keyPressEvent(QKeyEvent* event) {
    switch(event->key()) {
    case Qt::Key_Shift:
        ui->renderWidget->setShiftPressed(true);
        break;
    default:
        break;
    }
    QWidget::keyPressEvent(event);
}

void MainWindow::keyReleaseEvent(QKeyEvent* event) {
    switch(event->key()) {
    case Qt::Key_Shift:
        ui->renderWidget->setShiftPressed(false);
        break;
    default:
        break;
    }
    QWidget::keyReleaseEvent(event);
}



#define TAG_VERTEX_SCENE    "[FRQ_PERIODIC_VERTEX_SCENE]\n"
#define TAG_FRAGMENT_SCENE  "[FRQ_PERIODIC_FRAGMENT_SCENE]\n"
#define TAG_VERTEX_POST     "[FRQ_PERIODIC_VERTEX_POST]\n"
#define TAG_FRAGMENT_POST   "[FRQ_PERIODIC_FRAGMENT_POST]\n"
#define TAG_PARAMS          "[FRQ_PERIODIC_PARAMS]\n"


void MainWindow::open(){

    _filename = QFileDialog::getOpenFileName(NULL, QString("Open a period file"), QString("Scenes/"), QString("Periodic scene files (*.period)"));
    if(_filename.isEmpty())
        return;
    QFile file (_filename);
    if(!file.exists())
    {
        QMessageBox::critical(NULL, QString("Periodic - File opening"),QString("This file does not exist."));
        return;
    }
    file.open(QFile::ReadOnly);


    //Parsing file ..
    QString VertexSceneText,FragmentSceneText,VertexPostText,FragmentPostText,ParamText;
    QByteArray line;
    while (!file.atEnd())
    {

        //Scene shader
        if( line.startsWith(TAG_VERTEX_SCENE) ) {
                while (!file.atEnd()) {
                        line = file.readLine();
                        if( line.startsWith('[') ) {
                                break;
                        }
                        VertexSceneText.push_back(line);
                }

                continue;
        }
        if( line.startsWith(TAG_FRAGMENT_SCENE) ) {
                while (!file.atEnd()) {
                        line = file.readLine();
                        if( line.startsWith('[') ) {
                                break;
                        }
                        FragmentSceneText.push_back(line);
                }

                continue;
        }

        //Post processing shader
        if( line.startsWith(TAG_VERTEX_POST) ) {
                while (!file.atEnd()) {
                        line = file.readLine();
                        if( line.startsWith('[') ) {
                                break;
                        }
                        VertexPostText.push_back(line);
                }

                continue;
        }
        if( line.startsWith(TAG_FRAGMENT_POST) ) {
                while (!file.atEnd()) {
                        line = file.readLine();
                        if( line.startsWith('[') ) {
                                break;
                        }
                        FragmentPostText.push_back(line);
                }

                continue;
        }

        //Param
        if( line.startsWith(TAG_PARAMS) ) {
                while (!file.atEnd()) {
                        line = file.readLine();
                        if( line.startsWith('[') ) {
                                break;
                        }
                        ParamText.push_back(line);
                }

                continue;
        }

            line = file.readLine();
    }

    file.close();


    //Load data & compil shaders etc etc :))) !
    _shew->setVertexText(VertexSceneText);
    _shew->setFragmentText(FragmentSceneText);
    _shew->setVertexPostText(VertexPostText);
    _shew->setFragmentPostText(FragmentPostText);
    ui->renderWidget->CompilShader(VertexSceneText, FragmentSceneText);
    ui->renderWidget->CompilPostShader(VertexPostText, FragmentPostText);


    //Load curves
    //_cew->Clear();
    QStringList paramLines = ParamText.split("\n");
    foreach(QString pLine, paramLines)
    {
        if(pLine.isEmpty()) continue;
        QString pName = pLine.split(" | ").at(0);
        QStringList pPointList = pLine.split(" | ").at(1).split(" ");
        int nPoints = pPointList.at(0).toInt();
        pPointList.removeFirst();
        for(int i = 0; i < nPoints * 4; i += 4)
        {
            float px = pPointList.at(i).toFloat();
            float py = pPointList.at(i+1).toFloat();
            float tx = pPointList.at(i+2).toFloat();
            float ty = pPointList.at(i+3).toFloat();
            CurvePointItem* cpi = new CurvePointItem(QPointF(px, py), QPointF(tx, ty));
            _cew->addPointToCurve(cpi, pName);
        }
    }
    _cew->setMusicTime(0);
}

//Write : Name NbPoint pointTime1 pointValue1 pointTangeantX pointTangeantY pointTime2 pointValue2 [...]
void MainWindow::SaveRecursiveTree(QTextStream &stream, SceneEditorTreeItem* tree)
{
    if( !tree->childCount() )
    {
        QList<CurvePointItem*> *points = _cew->getCurve(tree->longVarName());
        stream << tree->longVarName() << " | " << points->size();
        for(int i=0; i<points->size(); i++)
        {
            stream << " " << points->at(i)->time() << " " << points->at(i)->value()
                   << " " << points->at(i)->tangent().x() << " " << points->at(i)->tangent().y();
        }
        stream << endl;
    }
    else
    {
        foreach(SceneEditorTreeItem* tmp, tree->children())
        {
            SaveRecursiveTree(stream, tmp);
        }
    }
}

void MainWindow::save(){
    if(_filename.isEmpty())
    {
        saveas();
        return;
    }
    //Open File
    QFile file(_filename);
    if( !file.open(QFile::WriteOnly) )
    {
        QMessageBox::information(this, "Save", "Can't write in "+_filename);
        return;
    }
    QTextStream stream( &file );

    //Write shaders data..
    //Scene shader
    stream << QString(TAG_VERTEX_SCENE);
    stream << _shew->getVertexText() << "\n";
    stream << QString(TAG_FRAGMENT_SCENE);
    stream << _shew->getFragmentText() << "\n";
    //Post Process shader
    stream << QString(TAG_VERTEX_POST);
    stream << _shew->getVertexPostText() << "\n";
    stream << QString(TAG_FRAGMENT_POST);
    stream << _shew->getFragmentPostText() << "\n";

    //Write param data..
    SceneEditorTreeItem* tree = ui->renderWidget->sceneTree();
    stream << QString(TAG_PARAMS);
    SaveRecursiveTree(stream,tree);

    file.close();
    QMessageBox::information(this, "Save", "Successful");
}

void MainWindow::saveas(){
    _filename = QFileDialog::getSaveFileName(NULL,QString("Save as .."),QString("Data"));
    if(!_filename.isEmpty())
    {
        save();
    }
}

void MainWindow::about(){
    QMessageBox::information(this, "About", "Visit www.FRequency.fr");
}
